package cn.initcap.algorithm.swing.sort.heap;

import cn.initcap.algorithm.swing.AlgoVisHelper;
import cn.initcap.algorithm.swing.BaseAlgoFrame;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;

/**
 * @author initcap
 * @date 2018/8/3 AM10:46
 */
public class AlgoVisualizer {

    private static int DELAY = 20;
    private HeapSortData data;
    private BaseAlgoFrame frame;

    public AlgoVisualizer(int sceneWidth, int sceneHeight, int n) {

        // 初始化数据
        data = new HeapSortData(n, sceneHeight);

        // 初始化视图
        EventQueue.invokeLater(() -> {
            frame = new BaseAlgoFrame("Heap Sort Visualization", sceneWidth, sceneHeight) {
                @Override
                public void draw(Graphics graphics) {
                    Graphics2D g2d = (Graphics2D) graphics;
                    int w = sceneWidth / data.N();
                    for (int i = 0; i < data.N(); i++) {
                        if (i >= data.heapIndex) {
                            AlgoVisHelper.setColor(g2d, AlgoVisHelper.RED);
                        } else {
                            AlgoVisHelper.setColor(g2d, AlgoVisHelper.GREY);
                        }
                        AlgoVisHelper.fillRectangle(g2d, i * w, sceneHeight - data.get(i), w - 1, data.get(i));
                    }
                }
            };

            new Thread(() -> {
                run();
            }).start();
        });
    }

    public static void main(String[] args) {

        int sceneWidth = 800;
        int sceneHeight = 700;
        int n = 100;

        new AlgoVisualizer(sceneWidth, sceneHeight, n);
    }

    public void run() {

        setData(data.N());

        // 建堆
        for (int i = (data.N() - 1 - 1) / 2; i >= 0; i--) {
            shiftDown(data.N(), i);
        }

        // 堆排序
        for (int i = data.N() - 1; i > 0; i--) {
            data.swap(0, i);
            shiftDown(i, 0);
            setData(i);
        }

        setData(0);
    }

    private void shiftDown(int n, int k) {

        while (2 * k + 1 < n) {
            int j = 2 * k + 1;
            if (j + 1 < n && data.get(j + 1) > data.get(j)) {
                j += 1;
            }
            if (data.get(k) >= data.get(j)) {
                break;
            }
            data.swap(k, j);
            setData(data.heapIndex);

            k = j;
        }
    }

    private void setData(int heapIndex) {

        data.heapIndex = heapIndex;

        frame.render(data);
        AlgoVisHelper.pause(DELAY);
    }
}